﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Newtonsoft.Json.Linq;
using System.IO.IsolatedStorage;
using System.IO;
using BitcoinMarket.Resources;
using Newtonsoft.Json;
using System.Collections.Generic;

namespace BitcoinMarket.DataSources
{
    public class BlockChainDataSource
    {
        private string HashRatePublicUrl = "http://blockchain.info/charts/hash-rate?timespan=1year&daysAverageString=7&scale=0&format=json";
        private string HashRateLocalUrl = "http://localhost/hash-rate.json";

        private string MarketsPricePublicUrl = "http://blockchain.info/charts/market-price?timespan=1year&daysAverageString=7&scale=0&format=json";
        private string MarketsPriceLocalUrl = "http://localhost/market-price.json";

        private string AvgConfirmTimePublicUrl = "http://blockchain.info/charts/avg-confirmation-time?timespan=1year&daysAverageString=7&scale=0&format=json";
        private string AvgConfirmTimeLocalUrl = "http://localhost/avg-confirmation-time.json";

        private string HashRateLocalDataFilename = "BlockChainHashRate_data.json";
        private string MarketsPriceLocalDataFilename = "BlockChainMarketsPrice_data.json";
        private string AvgConfirmTimeLocalDataFilename = "BlockChainAvgConfirmTime_data.json";

        private JArray ParsedHashRateData = null;
        private JArray ParsedMarketsPriceData = null;
        private JArray ParsedAvgConfirmTimeData = null;

        private JArray[] ParsedData = null;

        private Action<JArray> HashRateDownloadCallback = null;
        private Action<JArray> MarketsPriceDownloadCallback = null;
        private Action<JArray> AvgConfirmTimeDownloadCallback = null;

        private Action<JArray[]> DataDownloadCallback = null;

        private int LeftToDownload = 0;

        /// <summary>
        /// Downloads the JSON files from the web
        /// </summary>
        public void GetData(List<string> urls, Action<JArray[]> DownloadCallback)
        {
            //Allocate memory for the data storing array
            this.ParsedData = new JArray[urls.Count];

            //Set the download callback
            this.DataDownloadCallback = DownloadCallback;

            this.LeftToDownload = urls.Count;
            int i = 0;

            foreach (string url in urls)
            {
                //Download the JSON data from the web
                WebClient DataJSON = new WebClient();
                DataJSON.DownloadStringCompleted += new DownloadStringCompletedEventHandler(json_DataDownloadStringCompleted);

                try
                {
                    DataJSON.DownloadStringAsync(new Uri(url), i);
                }
                catch (Exception ex)
                {
                    //MessageBox.Show(ex.Message);
                    System.Diagnostics.Debug.WriteLine(ex.InnerException);
                }

                i++;
            }
        }

        /// <summary>
        /// Hash Rate JSON file downloaded callback
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void json_DataDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error != null) // could not download
            {
                //Tell the user
                //MessageBox.Show("BlockChain: Could not download new data. Data from the last successfull download will be used.");
                System.Diagnostics.Debug.WriteLine(e.Error.InnerException);
            }
            else // Successfully downloaded
            {
                string jsonstr = e.Result;
                int fileId = (int)e.UserState;

                //Parse JSON data into an object
                try
                {
                    JObject tmp = JObject.Parse(jsonstr);
                    JArray ParsedDataObj = (JArray)tmp["values"];

                    if (ParsedDataObj != null)
                    {
                        this.ParsedData[fileId] = ParsedDataObj;
                    }
                }
                catch (FormatException ex)
                {
                    MessageBox.Show(ex.Message);
                    System.Diagnostics.Debug.WriteLine(ex.Data);
                }
                catch (JsonReaderException ex)
                {
                    MessageBox.Show(ex.Message);
                    System.Diagnostics.Debug.WriteLine(ex.InnerException);
                }
            }

            //If everything is downloaded pass it to the callback
            if (--this.LeftToDownload <= 0)
            {
                this.DataDownloadCallback(this.ParsedData);
            }
        }


        /// <summary>
        /// Hash Rate JSON file downloaded callback
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void json_HashRateDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            string jsonstr = "";

            if (e.Error != null)
            {
                //Tell the user
                //MessageBox.Show("BlockChain: Could not download new data. Data from the last successfull download will be used.");
                System.Diagnostics.Debug.WriteLine(e.Error.InnerException);

                //Get last saved JSON data from a local file
                try
                {
                    IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
                    IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile(this.HashRateLocalDataFilename, FileMode.Open, FileAccess.Read);
                    using (StreamReader reader = new StreamReader(fileStream))
                    {
                        jsonstr = reader.ReadToEnd();
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(AppResources.BlockChainNoData);
                    System.Diagnostics.Debug.WriteLine(ex.InnerException);

                    return;
                }
            }
            else
            {
                jsonstr = e.Result;

                //Save the downladed data into alocal file
                IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();

                using (StreamWriter writeFile = new StreamWriter(new IsolatedStorageFileStream(this.HashRateLocalDataFilename, FileMode.OpenOrCreate, FileAccess.Write, myIsolatedStorage)))
                {
                    writeFile.Write(jsonstr);
                    writeFile.Close();
                }
            }

            //Parse JSON data into an object
            try
            {
                JObject tmp = JObject.Parse(jsonstr);
                this.ParsedHashRateData = (JArray)tmp["values"];

                if (this.ParsedHashRateData != null)
                {
                    this.HashRateDownloadCallback(this.ParsedHashRateData);
                }
            }
            catch (FormatException ex)
            {
                MessageBox.Show(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.Data);
            }
            catch (JsonReaderException ex)
            {
                MessageBox.Show(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.InnerException);
            }
        }

        /// <summary>
        /// Downloads the JSON files from the web
        /// </summary>
        public void GetHashRateData(Action<JArray> HashRateDownloadCallback)
        {
            //Set the download callbacks
            this.HashRateDownloadCallback = HashRateDownloadCallback;

            //Download the JSON data from the web
            WebClient HashRateJSON = new WebClient();
            HashRateJSON.DownloadStringCompleted += new DownloadStringCompletedEventHandler(json_HashRateDownloadStringCompleted);

            try
            {
                switch (Microsoft.Devices.Environment.DeviceType)
                {
                    case Microsoft.Devices.DeviceType.Device:
                        HashRateJSON.DownloadStringAsync(new Uri(this.HashRatePublicUrl));
                        break;
                    case Microsoft.Devices.DeviceType.Emulator:
                        HashRateJSON.DownloadStringAsync(new Uri(this.HashRateLocalUrl));
                        break;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.InnerException);
            }
        }



        /// <summary>
        /// Markets Price JSON file downloaded callback
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void json_MarketsPriceDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            string jsonstr = "";

            if (e.Error != null)
            {
                //Tell the user
                //MessageBox.Show("BlockChain: Could not download new data. Data from the last successfull download will be used.");
                System.Diagnostics.Debug.WriteLine(e.Error.InnerException);

                //Get last saved JSON data from a local file
                try
                {
                    IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
                    IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile(this.MarketsPriceLocalDataFilename, FileMode.Open, FileAccess.Read);
                    using (StreamReader reader = new StreamReader(fileStream))
                    {
                        jsonstr = reader.ReadToEnd();
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(AppResources.BlockChainNoData);
                    System.Diagnostics.Debug.WriteLine(ex.InnerException);

                    return;
                }
            }
            else
            {
                jsonstr = e.Result;

                //Save the downladed data into alocal file
                IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();

                using (StreamWriter writeFile = new StreamWriter(new IsolatedStorageFileStream(this.MarketsPriceLocalDataFilename, FileMode.OpenOrCreate, FileAccess.Write, myIsolatedStorage)))
                {
                    writeFile.Write(jsonstr);
                    writeFile.Close();
                }
            }

            //Parse JSON data into an object
            try
            {
                JObject tmp = JObject.Parse(jsonstr);
                this.ParsedMarketsPriceData = (JArray)tmp["values"];

                if (this.ParsedMarketsPriceData != null)
                {
                    this.MarketsPriceDownloadCallback(this.ParsedMarketsPriceData);
                }
            }
            catch (FormatException ex)
            {
                MessageBox.Show(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.Data);
            }
            catch (JsonReaderException ex)
            {
                MessageBox.Show(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.InnerException);
            }
        }

        /// <summary>
        /// Downloads the JSON files from the web
        /// </summary>
        public void GetMarketsPriceData(Action<JArray> MarketsPriceDownloadCallback)
        {
            //Set the download callbacks
            this.MarketsPriceDownloadCallback = MarketsPriceDownloadCallback;

            //Download the JSON data from the web
            WebClient MarketsPriceJSON = new WebClient();
            MarketsPriceJSON.DownloadStringCompleted += new DownloadStringCompletedEventHandler(json_MarketsPriceDownloadStringCompleted);

            try
            {
                switch (Microsoft.Devices.Environment.DeviceType)
                {
                    case Microsoft.Devices.DeviceType.Device:
                        MarketsPriceJSON.DownloadStringAsync(new Uri(this.MarketsPricePublicUrl));
                        break;
                    case Microsoft.Devices.DeviceType.Emulator:
                        MarketsPriceJSON.DownloadStringAsync(new Uri(this.MarketsPriceLocalUrl));
                        break;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.InnerException);
            }
        }



        /// <summary>
        /// Avg Confirmation Time JSON file downloaded callback
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void json_AvgConfirmTimeDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            string jsonstr = "";

            if (e.Error != null)
            {
                //Tell the user
                //MessageBox.Show("BlockChain: Could not download new data. Data from the last successfull download will be used.");
                System.Diagnostics.Debug.WriteLine(e.Error.InnerException);

                //Get last saved JSON data from a local file
                try
                {
                    IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
                    IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile(this.AvgConfirmTimeLocalDataFilename, FileMode.Open, FileAccess.Read);
                    using (StreamReader reader = new StreamReader(fileStream))
                    {
                        jsonstr = reader.ReadToEnd();
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(AppResources.BlockChainNoData);
                    System.Diagnostics.Debug.WriteLine(ex.InnerException);

                    return;
                }
            }
            else
            {
                jsonstr = e.Result;

                //Save the downladed data into alocal file
                IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();

                using (StreamWriter writeFile = new StreamWriter(new IsolatedStorageFileStream(this.AvgConfirmTimeLocalDataFilename, FileMode.OpenOrCreate, FileAccess.Write, myIsolatedStorage)))
                {
                    writeFile.Write(jsonstr);
                    writeFile.Close();
                }
            }

            //Parse JSON data into an object
            try
            {
                JObject tmp = JObject.Parse(jsonstr);
                this.ParsedAvgConfirmTimeData = (JArray)tmp["values"];

                if (this.ParsedAvgConfirmTimeData != null)
                {
                    this.AvgConfirmTimeDownloadCallback(this.ParsedAvgConfirmTimeData);
                }
            }
            catch (FormatException ex)
            {
                MessageBox.Show(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.Data);
            }
            catch (JsonReaderException ex)
            {
                MessageBox.Show(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.InnerException);
            }
        }

        /// <summary>
        /// Downloads the JSON files from the web
        /// </summary>
        public void GetAvgConfirmTimeData(Action<JArray> AvgConfirmTimeDownloadCallback)
        {
            //Set the download callbacks
            this.AvgConfirmTimeDownloadCallback = AvgConfirmTimeDownloadCallback;

            //Download the JSON data from the web
            WebClient AvgConfirmTimeJSON = new WebClient();
            AvgConfirmTimeJSON.DownloadStringCompleted += new DownloadStringCompletedEventHandler(json_AvgConfirmTimeDownloadStringCompleted);

            try
            {
                switch (Microsoft.Devices.Environment.DeviceType)
                {
                    case Microsoft.Devices.DeviceType.Device:
                        AvgConfirmTimeJSON.DownloadStringAsync(new Uri(this.AvgConfirmTimePublicUrl));
                        break;
                    case Microsoft.Devices.DeviceType.Emulator:
                        AvgConfirmTimeJSON.DownloadStringAsync(new Uri(this.AvgConfirmTimeLocalUrl));
                        break;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.InnerException);
            }
        }
    }
}
